#include <iostream>
#include <iomanip>
#include <cmath>
#include <iomanip>
#include <string.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
using namespace std;
#include "test.h"

void work(int sockid,struct sockaddr_in addr)
{
     cout<<"我收到了一个套接字，值为："<<sockid<<endl;;
}

class tcpServer
{
private:
     int sID;
     tcpServer(const char * pIP , ushort port)
     {
          struct sockaddr_in sin;
          sin.sin_family = AF_INET;//IPV4的网络地址版本
          sin.sin_port = htons(port);//把9000号端口转为网络字节序并赋值给端口参数

          u_int32_t ip = 0;
          //把字符串ip地址转为网络字节序ip
          inet_pton(AF_INET,pIP,&ip);
          sin.sin_addr.s_addr = ip;

          //创建一个tcp套接字，参数1指定地址族，参数2指定协议，SOCK_STREAM代表是TCP，SOCK_DGRAM代表UDP
          sID = socket(AF_INET,SOCK_STREAM,0);

          //把套接字和地址绑定（手机+手机号）
          bind(sID,(struct sockaddr*)&sin,sizeof(sin));

          //打开监听功能，监听绑定地址上的来访请求，5代表同时允许5个客户端排队连接
          listen(sID,5);
     }
public:
     static tcpServer * getServer(const char * IP,ushort port)
     {
          static tcpServer tcp(IP,port);
          return &tcp;
     }
     void run(void (*pFun)(int sockid,struct sockaddr_in addr))
     {
          while (1)
          {
               struct sockaddr_in clientAddr;
               socklen_t len = sizeof(clientAddr);
               //接受客户端连接，参数1：是套接字的ID，参数2：用来存放客户端地址的结构体，参数3：客户端地址结构体的长度
               //该函数会返回一个新的套接字，用来和连接上的客户端通信
               //如果没有客户端连接，accept会阻塞
               int newSockID = accept(sID,(struct sockaddr*)&clientAddr,&len);
               pFun(sID,clientAddr);//调用外面的work函数
          }
     }
};


int main()
{
     tcpServer::getServer("192.168.50.143",9999)->run(work);//服务器开始运行了
     return 0;
}